﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Net;
using System.IO;


namespace Qurihara.OSCCom
{
    class TcpComServer
    {
        private TcpListener listener = null;

        //サーバ側のストリーム
        private StreamWriter serverWriter = null;
        private StreamReader serverReader = null;

        //サーバスレッド
        Thread threadServer = null;

        protected bool readerConnected = false;
        public bool ReaderConnected
        {
            get { return readerConnected; }
        }
        protected bool writerConnected = false;
        public bool WriterConnected
        {
            get { return writerConnected; }
        }

        public class TcpMessageEventArgs : EventArgs
        {
            public TcpMessageEventArgs(string s)
            {
                Message = s;
            }
            public string Message;
        }
        public delegate void TcpMessageEventHandler(object o, TcpMessageEventArgs e);
        public event TcpMessageEventHandler TcpMessageReceived;


        public TcpComServer()
        {
        }

        //サーバをスタート
        public bool ServerStart(int port)
        {
            try
            {
                //TcpListenerを使用してサーバーを指定のポートで確立
                listener = new TcpListener(IPAddress.Any, port);
                listener.Start();

                //スレッドとしてクライアントからの通信を処理する部分を実行
                threadServer = new Thread(new ThreadStart(ServerListen));
                threadServer.Start();
                return true;
            }
            catch (Exception exception)
            {
                return false;
            }
        }
        //UIとは別スレッドで実行されるサーバ側の処理
        private void ServerListen()
        {
            try
            {
                //クライアントの要求があったら、接続を確立する
                TcpClient server = listener.AcceptTcpClient();

                //クライアントとの間の通信につかうストリームを取得
                NetworkStream ns = server.GetStream();

                serverReader = new StreamReader(ns, Encoding.UTF8);
                //serverWriter = new StreamWriter(ns, Encoding.UTF8);

                readerConnected = true;

                //クライアントからのデータ送信をループで待機
                //いつデータ送信がきても受信するように
                while (true)
                {
                    ProcessMessage(serverReader);
                }
            }
            catch (Exception exception)
            {
            }
        }
        //受け取ったメッセージを処理する
        protected virtual void ProcessMessage(StreamReader reader)
        {
            string message;
            lock (this)
            {
                message = reader.ReadLine();
            }
            if (TcpMessageReceived != null) TcpMessageReceived(this, new TcpMessageEventArgs(message));

        }

        //すべての接続を破棄し、スレッドを終了させる
        public virtual void Dispose()
        {
            if (listener != null)
            {
                listener.Stop();
            }

            if (serverReader != null)
            {
                serverReader.BaseStream.Close();
                serverReader.Close();
            }

            if (serverWriter != null)
            {
                serverWriter.Close();
            }

            if (threadServer != null)
            {
                threadServer.Abort();
            }
        }

        public void ConnectTransmitter(string serverIP, int serverPort)
        {
            try
            {
                TcpClient client = new TcpClient(serverIP, serverPort);
                NetworkStream ns = client.GetStream();

                serverWriter = new StreamWriter(ns, Encoding.UTF8);
                writerConnected = true;
            }
            catch
            {
            }
        }

        //データを送るメソッド
        public virtual void SendMessage(string messageLine)
        {
            if (writerConnected)
            {
                serverWriter.WriteLine(messageLine);
                //確実にネットワークに流れるようにFlush
                serverWriter.Flush();
            }
        }

    }
}
